package main
import (
	"fmt"
	"reflect"
	"encoding/json"
)
//反射的最佳实践(2)

//使用反射来修改结构体的字段，调用结构体的方法，并且获取结构体标签的值
func main(){
	//创建一个Monster实例
	var m Monster = Monster{
		Name : "黄鼠狼",
		Age: 400,
		Score:38.9,
	}
	//将实例传入函数
	TestStruct(&m)

	str,err := json.Marshal(m)
	if err == nil {
		fmt.Println("序列化后：",string(str))
	}
}

type Monster struct{
	Name string `json:"name"`
	Age int `json:"monster_age"`
	Score float64 
	Sex string
}
func (m Monster)Print(){
	fmt.Println("---start---")
	fmt.Println("---",m,"---")
	fmt.Println("---end---")
}
func (m Monster)GetSum(n1,n2 int)int{
	return n1+n2
}
func (m Monster)Set(name string,age int,score float64,sex string){
	m.Name = name
	m.Age = age
	m.Score = score
	m.Sex = sex
}

func TestStruct(a interface{}){
	typ := reflect.TypeOf(a)
	val := reflect.ValueOf(a)
	kd := val.Kind()
	if kd != reflect.Ptr &&  val.Elem().Kind() == reflect.Struct{     //**************
		fmt.Println("No a Struct")
		return
	}
	num := val.Elem().NumField()   //**************
	fmt.Printf("该结构体一共有%d个字段\n",num)
	val.Elem().Field(0).SetString("白骨精")   //**************
	for i := 0;i < num;i++{
		fmt.Printf("第%d个字段的类型是%v\n",i,val.Elem().Field(i).Kind())   //**************
	}

	tag := typ.Elem().Field(0).Tag.Get("json")  //tag is string   //**************
	fmt.Println("第一个字段的标签是：",tag)
	
	numOfMethod := val.Elem().NumMethod()   //**************
	fmt.Printf("该结构体一共绑定了%d个方法\n",numOfMethod)
	//现在执行第2个Print方法输出结构体信息
	val.Elem().Method(1).Call(nil) //无需传入参数   //**************
}
